package basics.cankao;

import basics.annotation.AParameter;
import basics.annotation.Actioner;
import basics.annotation.Service;
import basics.test.MethodParameterNotDefineException;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Ldanniel
 * @description :
 * @date 2022/11/01 22:25
 * @since open jdk 1.8
 */

public class ActionFactory {
    private static final Map<String, ActionDefination> actionDefinationMap = new HashMap<String, ActionDefination>();

    // 单例模式
    ActionFactory() {
    }
    public static ActionFactory newInstance() {
        return creatNewInstance.actionFactory;
    }

    private static class creatNewInstance {
        private static final ActionFactory actionFactory = new ActionFactory();
    }

    // 通过类，扫描其所在包下的所有文件
    public void scanAction(Class<?> klass) {
        scanAction(klass.getPackage().getName());
    }

    //  通过包名称，扫描其下所有文件
    public void scanAction(String packageName) {
        // 包扫描，在我的上一篇博客有该方法的实现
        new PackageScanner() {
            @Override
            public void dealClass(Class<?> klass) {
                // 只处理带有Service注解的类
                if (!klass.isAnnotationPresent(Service.class)) {
                    return;
                }
                try {
                    // 直接由反射机制产生一个对象，将其注入
                    Object object = klass.newInstance();
                    // 扫描改类下的所有方法
                    scanMethod(klass, object);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.scanPackage(packageName);
    }

    // 通过对象，扫描其所有方法
    public void scanAction(Object object) {
        try {
            scanMethod(object.getClass(), object);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void scanMethod(Class<?> klass, Object object) throws Exception {
        // 得到所有方法
        Method[] methods = klass.getDeclaredMethods();

        // 遍历所有方法，找到带有Actioner注解的方法，并得到action的值
        for (Method method : methods) {
            if (!method.isAnnotationPresent(Actioner.class)) {
                continue;
            }
            Actioner actioner = method.getAnnotation(Actioner.class);
            String action = actioner.action();

            // 判断action是否已经定义
            if (actionDefinationMap.get(action) != null) {
                throw new ActionHasDefineException("方法" + action + "已定义！");
            }

            // 得到所有参数，并判断参数是否满足要求
            Parameter[] parameters = method.getParameters();
            List<Parameter> parameterList = new ArrayList<Parameter>();
            for (int i = 0; i < parameters.length; i++) {
                Parameter parameter = parameters[i];
                if (!parameters[i].isAnnotationPresent(AParameter.class)) {
                    throw new MethodParameterNotDefineException("第" + (i+1) + "个参数未定义！");
                }

                parameterList.add(parameter);
            }
            // 将得到的结果添加到map中
            addActionDefination(action, klass, object, method, parameterList);
        }
    }

    private void addActionDefination(String action, Class<?> klass, Object object, Method method, List<Parameter> parameterList) {
        ActionDefination actionDefination = new ActionDefination(klass, object, method, parameterList);
        actionDefinationMap.put(action, actionDefination);
    }

    protected ActionDefination getActionDefination(String action) {
        return actionDefinationMap.get(action);
    }

}